package com.nicolasprof.profgallery.navigation {
	import gs.TimelineLite;
	import gs.TweenLite;
	import gs.easing.Sine;

	import com.nicolasprof.profgallery.Engine;
	import com.nicolasprof.profgallery.navigation.scrollbar.ScrollBar;
	import com.nicolasprof.profgallery.navigation.scrollbar.ScrollBarEvent;

	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;

	/**
	 * @author Nicolas Prof
	 */
	public class Categories extends Object {

		protected var _engine : Engine;
		protected var _block : BlockLayer;
		protected var _holder : Sprite;
		protected var _selected : Node;
		protected var _curLevel : int;
		protected var _sb : ScrollBar;
		protected var _mask : Rectangle;
		protected var _curScroll : int;
		protected var _nodeHeight : int;
		protected var _marginY : int;
		protected var _rows : int;

		
		
		
		
		public function Categories($engine : Engine) {
			var config: XML = Engine.CONFIG_XML;
			_engine = $engine;
			_holder = new Sprite();
			_marginY = int(config.navigationCustomize.@marginY);
			_rows = int(config.navigationCustomize.@rows);
			_holder.x = config.navigationCustomize.@posX;
			_holder.y = config.navigationCustomize.@posY;
		}
		public function build() : void {
			_block= new BlockLayer();
			var data : XML = Engine.CONFIG_XML.navigation[0];
			
			//Listeners
			_block.addEventListener(MouseEvent.CLICK, onClickBackground, false, 0, true);
			
			//Display list
			_engine.stage.addChild(_block);
			_engine.stage.addChild(_holder);
			
			//Actions
			_block.draw();
			constructLayer(data, 0);
		}
		protected function checkScrollBar() : void {
			if(_holder.numChildren > _rows) {
				createScrollBar();
			}else{
				removeScrollBar();
			}
		}
		protected function clearAll() : void {
			_selected = null;
			_mask = null;
			_curScroll = 0;
			_block.removeEventListener(MouseEvent.CLICK, onClickBackground);
			deleteNodes();
			removeScrollBar();
		}
		protected function constructLayer($data: XML, $index : int) : void {
			_curLevel = $index;
			var i:int;
			var len:int = $data.menu.length();
			
			for (i = 0; i < len; i++) {
				var node : Node = new Node($data.menu[i], $index);
				
				//Listeners
				node.addEventListener(MouseEvent.CLICK, onClickNode, false, 0, true);
				
				_nodeHeight = node.height;
				node.y = ($index + i) * (_marginY + _nodeHeight);
				TweenLite.from(node, 0.5, {autoAlpha:0, blurFilter:{blurX:10, blurY:10, quality:3}, delay: i*0.25});
				
				_holder.addChild(node);
			}
			
			checkScrollBar();
		}
		protected function createScrollBar() : void {
			if(_sb == null){
				var config: XML = Engine.CONFIG_XML;
				var marginX : int = int(config.navigationCustomize.@marginX);
				_sb = new ScrollBar();
				_mask = new Rectangle(0, 0, _holder.width, _rows * (_marginY + _holder.getChildAt(0).height) - _marginY);
				_engine.stage.addChild(_sb);
				
				_sb.addEventListener(ScrollBarEvent.CHANGE, onChangeScrollbar, false, 0, true);
				_sb.addEventListener(ScrollBarEvent.MOVE, onChangeScrollbar, false, 0, true);
				
				_sb.x = _holder.x + _holder.width + marginX;
				_sb.y = _holder.y;
				_sb.initiate(_mask.height, _mask.height / _holder.height, 0);
				
			}
			scrollToSelected();		
		}
		protected function deleteAll() : void {
			while(_holder.numChildren) {
				_holder.removeChildAt(0);
			}
			_engine.stage.removeChild(_holder);
		}
		protected function deleteNodes() : void {
			var i: int = _holder.numChildren;
			var j: int;
			var node : Node;
			var line: TimelineLite = new TimelineLite({onComplete:deleteAll});
			while(i--){
				node = _holder.getChildAt(i) as Node;
				node.mouseEnabled = false;
				node.removeEventListener(MouseEvent.CLICK, onClickNode);
				line.insert(TweenLite.to(node, 0.5, {autoAlpha:0, y:0, ease: Sine.easeInOut}), j*0.15);
				j++;
			}
		}
		protected function deleteNodesAt($level : int, $node: Node = null) : void {
			var i: int = _holder.numChildren;
			var node: Node;
			while(i--) {
				node = _holder.getChildAt(i) as Node;
				if(node.level == $level && node != $node) {
					node.removeEventListener(MouseEvent.CLICK, onClickNode);
					_holder.removeChild(node);
				}
			}
		}
		protected function deleteNodesFrom($level : int) : void {
			var i: int = _holder.numChildren;
			var node: Node;
			while(i--) {
				node = _holder.getChildAt(i) as Node;
				if(node.level >= $level) {
					node.removeEventListener(MouseEvent.CLICK, onClickNode);
					_holder.removeChild(node);
				}
			}
		}
		protected function getHolderHeight() : Number {			
			return _holder.numChildren * (_nodeHeight + _marginY);
		}
		protected function getScrollHeight() : Number {
			return (_holder.numChildren - _rows) * (_nodeHeight + _marginY);
		}
		protected function manageSelected($node : Node) : void {
			deleteNodesAt($node.level, $node);
			TweenLite.to($node, 0.5, {y:$node.level * (_marginY + _nodeHeight), colorMatrixFilter:{brightness:0}});
		}	
		public function removeBlockLayer() : void {
			if(_block != null){
				_block.remove();
				_block = null;
			}
		}
		protected function removeScrollBar() : void {
			if(_sb != null){
				_engine.stage.removeChild(_sb);
				_holder.scrollRect = null;
				_sb.removeEventListener(ScrollBarEvent.CHANGE, onChangeScrollbar);
				_sb.removeEventListener(ScrollBarEvent.MOVE, onChangeScrollbar);
				_sb = null;
			}
		}
		protected function scrollTo($posY : int) : void {
			TweenLite.to(_mask, 0.5, {y:$posY, onUpdate:updateMask});
		}
		protected function scrollToSelected() : void {
			_curScroll = (_curLevel > _holder.numChildren - _rows) ? _holder.numChildren - _rows : _curLevel;
			var posY: int = _curScroll * (_marginY + _nodeHeight);
			
			this.scrollTo(posY);
			
			_sb.updateBar(_mask.height / getHolderHeight());
			_sb.setPos(posY / getScrollHeight());
		}
		protected function updateMask() : void {
			_holder.scrollRect = _mask;
		}
		/**
		 * Events
		 */
		private function onChangeScrollbar(e : ScrollBarEvent) : void {
			var ratio: Number = e.ratio;
			var scroll: int = Math.round((getScrollHeight() * ratio) / (_nodeHeight + _marginY));
			if(scroll != _curScroll) {
				_curScroll = scroll;
				scrollTo(scroll * (_marginY + _nodeHeight));
			}
		}
		private function onClickBackground(e : MouseEvent) : void {
			clearAll();
			removeBlockLayer();
		}
		private function onClickNode(e : MouseEvent) : void {
			var node: Node = e.currentTarget as Node;
			if(node.multiSection){
				if(_curLevel > node.level){
					deleteNodesFrom(node.level);
					constructLayer(node.data.parent(), node.level);
				} else{
					manageSelected(node);
					constructLayer(node.data, node.level + 1);
				}
			} else {
				_engine.updateCategory(node.data.@url);
				clearAll();
			}
			
		}
		
		
	}
}
